import functools
import json
import logging
import os
import sys
from datetime import datetime
from logging.handlers import TimedRotatingFileHandler
from time import sleep
from typing import Union, Any, Iterable

import redis
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By

from const import cfg

log_path = f"{os.path.dirname(__file__)}/../logs"
if not os.path.exists(log_path):
    os.mkdir(log_path)
handlers = [TimedRotatingFileHandler(f'{log_path}/my_mirai.log', when="midnight", backupCount=5, encoding="utf-8"),
            logging.StreamHandler(sys.stdout)]
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s [%(levelname)s] [%(module)s-%(threadName)s]  %(lineno)d - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    handlers=handlers
)
logging.info("日志 > %s", os.path.abspath(log_path))

logger = logging.getLogger()

REDIS_POOL = None

if "redis" in cfg:
    host = cfg["redis"].get("host") or "192.168.227.129"
    port = cfg["redis"].get("port") or 6379
    db = cfg["redis"].get("db") or 0
    REDIS_POOL = redis.ConnectionPool(host=host, port=port, db=db)


def identity(x):
    return x


def group(funcs: Iterable, obj: Iterable) -> list[list, ...]:
    """
    分组
    :param funcs: 条件函数
    :param obj: 待分类对象
    :return: 分类后的数据
    """
    res = [[] for _ in funcs]
    for it in obj:
        for i, fun in enumerate(funcs):
            if fun(it):
                res[i].append(it)
    return res


def map_list(fun, obj):
    return list(map(fun, obj))


def filter_list(fun, obj):
    return list(filter(fun, obj))


def get_problem_png_path() -> tuple[str, dict[str, Union[list, Any]]]:
    if REDIS_POOL is None:
        logger.warning("只有配置了redis， 才能使用此功能")
    url = "https://leetcode.cn/problemset/all/?page=1"


    problem_bitmap = "leetcode:problemset:bitmap"
    redis_cli = redis.Redis(connection_pool=REDIS_POOL)
    has_solved_count = redis_cli.bitcount(problem_bitmap)
    ind = 0
    while redis_cli.getbit(problem_bitmap, ind):
        ind += 1

    options = webdriver.FirefoxOptions()
    options.add_argument("--headless")
    options.add_argument("--disable-gpu")
    options.add_argument("--disable-dev-shm-usage")
    driver = webdriver.Firefox(
        executable_path=r"D:\geckodriver.exe", options=options)
    try:
        driver.set_window_size(499, 1500)
        driver.get(url)
        driver.find_element(By.CSS_SELECTOR, "button.flex:nth-child(3)").click()
        soup = BeautifulSoup(driver.page_source)
        qs = json.loads(soup.select_one("#__NEXT_DATA__").text)[
            "props"]["pageProps"]["problemsetQuestionList"]["questions"]
        questions = list(map(
            lambda q: {"ind": q["frontendQuestionId"],
                       "title": q["titleCn"],
                       "titleSlug": q["titleSlug"],
                       "tags": list(map(lambda topic_tag: topic_tag["nameTranslated"], q["topicTags"]))
                       },
            qs
        ))

        target_question = list(filter(lambda q: q["ind"] == str(ind), questions))[0]
        q_url = f"https://leetcode.cn/problems/{target_question['titleSlug']}/"

        driver.get(q_url)

        sleep(3)
        buttons = driver.find_elements(By.CSS_SELECTOR, "button")
        for button in buttons:
            if "关闭" in button.text:
                button.click()
                break
        img_path = "print.png"
        driver.save_screenshot(img_path)
        return os.path.abspath(img_path), target_question
    finally:
        driver.quit()


def solved_problems(ind: int):
    if REDIS_POOL is None:
        raise RuntimeError("只有配置了redis， 才能使用此功能")
    problem_bitmap = "leetcode:problemset:bitmap"
    redis_cli = redis.Redis(connection_pool=REDIS_POOL)
    redis_cli.select(0)
    return redis_cli.setbit(problem_bitmap, ind, 1)


def unsolved_problems(ind: int):
    if REDIS_POOL is None:
        raise RuntimeError("只有配置了redis， 才能使用此功能")
    problem_bitmap = "leetcode:problemset:bitmap"
    redis_cli = redis.Redis(connection_pool=REDIS_POOL)
    redis_cli.select(0)
    return redis_cli.setbit(problem_bitmap, ind, 0)


def exec_redis_cmd(content: str) -> Any:
    args = content.split()
    redis_cli = redis.Redis(connection_pool=REDIS_POOL)
    res = redis_cli.execute_command(*(args))
    try:
        def decd(res):
            if isinstance(res, bytes):
                res = res.decode("utf-8")
            return res
        res = decd(res)
        if isinstance(res, (list, set)):
            res = map_list(decd, res)
        return json.dumps(json.loads(res), ensure_ascii=False, indent=2)
    except:
        return res


def msg_record(msg: Any,
               db: int = 0,
               key=None,
               value_fun=functools.partial(json.dumps, ensure_ascii=False),
               ex=7 * 24 * 3600
               ):
    redis_cli = redis.Redis(connection_pool=REDIS_POOL)
    redis_cli.select(db)
    res = redis_cli.lpush(key or datetime.now().strftime("%d-%H:%M"), value_fun(msg))
    redis_cli.expire(key or datetime.now().strftime("%d-%H:%M"), ex)
    return res
